


/*
 - INIT: TableAdapter<CONTAINER>
   - setup COLUMN adapters <OBJECT, RETURN_VALUE, [PROXY_TYPE]> => NAME

 - CREATION: TableRenderer
   - select columns (0,=>NULL;1=>contract to NEW_List!)
   - filter rows
   - select sorting (COLUMN, ORDER)

----------------------------------------------------------

TableRenderer tr(TableAdapter);

tr->selectColumn("Name");
tr->unSelectColumn("URI");
tr->filterBy("Priority", 12, 0);
tr->sortBy("Name", ASC);
Table* oTbl = tr.create();


struct TableSectionSettings {
	bool visible;
	short filter_mode; //-1 disabled
	short sort_mode; //-1 disabled

};
--

TableAdapter* tblA = new TableAdapter(myList);

MethodList->setTableAdapter(tblA);

class TableRenderer {


		Table* create() {
			
			FOR-EACH (ROW) {
				FOR-EACH (SELECTED_COL) {
					
					ISerializable* data = NULL;
					
					// FILTER, how!?
					
					data = tblAdapter.extract( COL_NAME );
					
					tbl->set( data , ROW, COL_INDEX);
					
				 }
			 }
			
			// SORT
		}

		TableAdapter tblAdapter;
		std::vector<std::string> selectedColumns;

};

*/



///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------

template <class OBJECT_TYPE>
class ITableSectionWrapper {
	public:
		virtual ISerializable* extract( OBJECT_TYPE* object ) const = 0;
		virtual ISerializable* getHeader() const = 0;
	public:
		virtual ~ITableSectionWrapper() { }
 };

///----------------------------------------------------------------------------------------------------------------------

template <class OBJECT_TYPE, typename VALUE_TYPE, class PROXY_TYPE>
class TableSectionWrapper : public ITableSectionWrapper<OBJECT_TYPE>
 {
	public:
		typedef VALUE_TYPE (OBJECT_TYPE::*MethodExtractor)(void) const;
	public:
		explicit TableSectionWrapper(MethodExtractor fptr, const Variant& optHeader = Variant::EmptyVariant ) 
			: fExtractorPtr(fptr), header(optHeader) { }
	public:
		ISerializable* extract( OBJECT_TYPE* object ) const {
			return new PROXY_TYPE( (object->*fExtractorPtr)() );
		 }
		ISerializable* getHeader() const		{ return this->header.clone(); }

	public:
		void setHeader( const Variant& value )	{ this->header = value; }
		Variant& getHeader()					{ return this->header; }

	private:
		MethodExtractor fExtractorPtr;
		Variant header;
};

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------

class ITableAdapter {
	public:
		virtual void clearSections() = 0;
		virtual unsigned int getSectionCount() const = 0;
		virtual unsigned int getItemCount() const = 0;
		virtual unsigned int loadItems() = 0 ;
		virtual void renderHeader( Table* tbl, bool horizontal = true, bool vertical = false ) = 0;
		virtual void renderSection( Table* tbl, unsigned int section_index, int table_index = -1 ) = 0;
		virtual void renderSections( Table* tbl ) = 0;
	public:
		virtual ~ITableAdapter() { }
};

///----------------------------------------------------------------------------------------------------------------------

template <class CONTAINER_TYPE, class OBJECT_TYPE, unsigned int TBL_SECTIONS>
class TableAdapter : public ITableAdapter
 {
	public:
		TableAdapter( const CONTAINER_TYPE& list )
			: ITableAdapter(), dataset(list) {
			clearSections();
		 }
		virtual ~TableAdapter() { }

	public:
		unsigned int loadItems() {
			this->items.clear();
			typename CONTAINER_TYPE::ConstIterator it_o;
			const typename CONTAINER_TYPE::ConstIterator it_o_end = this->dataset.end();
			for ( it_o=this->dataset.begin(); it_o!=it_o_end; ++it_o) {
				this->items.push_back(*it_o);
			 }
			return this->items.size();
		 }

		void renderSection( Table* tbl, unsigned int section_index, int table_index = -1 ) {
			if ( tbl == NULL ) return;
			unsigned int iRow = 0;
			if ( table_index <= -1 )
				table_index = section_index;
			std::vector<OBJECT_TYPE*>::iterator it_o;
			const std::vector<OBJECT_TYPE*>::const_iterator it_o_end = this->items.end();
			for ( it_o=this->items.begin(); it_o!=it_o_end; ++it_o, ++iRow ) {
				if ( this->cellRenderer[section_index] == NULL ) continue;
				ISerializable* vCell = this->cellRenderer[section_index]->extract( *it_o );
				tbl->set( vCell, iRow, table_index);
			 }
		 }

		void renderSections( Table* tbl ) {
			if ( tbl == NULL ) return;
			for ( unsigned int col=0; col<TBL_SECTIONS; ++col ) {
				renderSection(tbl, col);
			 }
		 }

		void renderHeader( Table* tbl, bool horizontal = true, bool vertical = false ) {
			if ( tbl == NULL ) return;
			if ( horizontal ) {
				if ( !tbl->hasHeaderHorizontal() )
					tbl->allocHeaderHorizontal(true);
				for ( unsigned int col=0; col<TBL_SECTIONS; ++col ) {
					tbl->setHeaderHorizontal( cellRenderer[col]->getHeader(), col);
				 }
			 }
			if ( vertical ) {
				if ( !tbl->hasHeaderVertical() )
					tbl->allocHeaderVertical(true);
				for ( unsigned int col=0; col<TBL_SECTIONS; ++col ) {
					tbl->setHeaderVertical( cellRenderer[col]->getHeader(), col);
				 }
			 }
		 }
/*
		template <typename VALUE_TYPE, class PROXY_TYPE>
		WRESULT createSection( unsigned int index, TableSectionWrapper<OBJECT_TYPE, VALUE_TYPE, PROXY_TYPE>::MethodExtractor fptr, const Variant& header = Variant::EmptyVariant ) {
			if ( index < 0 || index > TBL_SECTIONS ) return WRET_ERR_PARAM;
			this->cellRenderer[index] = = new TableSectionWrapper<OBJECT_TYPE, VALUE_TYPE, PROXY_TYPE>(fptr, header);
			return WRET_OK;
		 }
*/
	public:
		WRESULT setSection( unsigned int index, ITableSectionWrapper<OBJECT_TYPE>* tsw ) {
			if ( index < 0 || index > TBL_SECTIONS ) return WRET_ERR_PARAM;
			this->cellRenderer[index] = tsw;
			return WRET_OK;
		 }
		void clearSections() {
			for ( unsigned int col=0; col<TBL_SECTIONS; ++col ) {
				cellRenderer[col] = NULL;
			 }
		 }
		unsigned int getSectionCount() const	{ return TBL_SECTIONS; }
		unsigned int getItemCount() const		{ return this->dataset.size(); }

	private:
		const CONTAINER_TYPE& dataset;
		std::vector<OBJECT_TYPE*> items;
		ITableSectionWrapper<OBJECT_TYPE>* cellRenderer[TBL_SECTIONS];
};

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------
enum HEADER_MODE {
	HEADER_NONE			= 0x00,
	HEADER_HORIZONTAL	= 0x01,
	HEADER_VERTICAL		= 0x02
 };
enum SORT_ORDER {
	SORT_UNORDERED		= 0x00,
	SORT_ASCENDING		= 0x01,
	SORT_DESCENDING		= 0x02
 };
enum FILTER_MODE {
	FILTER_NONE			= 0x00,
	FILTER_EQUAL		= 0x01,
	FILTER_NOT_EQUAL	= 0x02,
	FILTER_GREATER		= 0x03,
	FILTER_LESS			= 0x04
 };

struct TableSectionSettings {
	TableSectionSettings()
		: section_index(-1), visible(true), filter_mode(0), sort_mode(0) { }

	int section_index;
	bool visible;
	short filter_mode;
	short sort_mode;

};

///----------------------------------------------------------------------------------------------------------------------

class TableRenderer
 {
	public:
		TableRenderer( ITableAdapter* table_adapter )
			: adapter(NULL), render_header(HEADER_HORIZONTAL) {
			setTableAdapter(table_adapter);
		 }
		virtual ~TableRenderer() {
			setTableAdapter(NULL);
		 }

	public:
		Table* create() {
			if ( this->adapter == NULL ) return NULL;
			Table* tbl = new Table(this->adapter->getItemCount(), this->adapter->getSectionCount());
			this->adapter->renderHeader( tbl, (this->render_header & HEADER_HORIZONTAL), (this->render_header & HEADER_VERTICAL) );
			if ( this->settings.empty() ) {
				this->adapter->renderSections( tbl );
				return tbl;
			 }

			unsigned int count = this->adapter->loadItems();
			// FILTER
			
			// SORT


			unsigned int iCol = 0;
			std::vector<TableSectionSettings>::const_iterator it;
			for ( it=this->settings.begin(); it!=this->settings.end(); ++it ) {
				if ( !(*it).visible ) continue;
				this->adapter->renderSection( tbl, (*it).section_index, iCol++ );
			 }

			return tbl;
		 }


	public:
		void setTableAdapter( ITableAdapter* table_adapter, bool enable_all_sections = true ) {
			this->adapter = table_adapter;
			if ( enable_all_sections )
				selectSections(true);
		 }

		void selectSection( unsigned int index, bool visible = true ) {
			while ( this->settings.size() < index+1 )
				this->settings.push_back( TableSectionSettings() );

			this->settings[index].section_index = index;
			this->settings[index].visible = visible;
		 }
		void selectSection( const Variant& header, bool enabled = true ) {
			if ( this->adapter == NULL ) return;
		 }
		void selectSections( bool enabled = true ) {
			if ( !enabled )
				this->settings.clear();
			else {
				if ( this->adapter == NULL ) return;
				for ( unsigned int col=0; col<this->adapter->getSectionCount(); ++col )
					selectSection(col);
			 }
		 }

	public:
		std::vector<TableSectionSettings>& getSettings()	{ return this->settings; }

	protected:
		ITableAdapter* adapter;
		std::vector<TableSectionSettings> settings;
		short render_header;
};

///----------------------------------------------------------------------------------------------------------------------
///----------------------------------------------------------------------------------------------------------------------

class Object_TableSectionWrapper : public ITableSectionWrapper<Object>
 {
	public:
		ISerializable* extract( Object* object ) const {
			return new Variant( object->getPermission().getMask() );
		}
		ISerializable* getHeader() const { return new Variant("Mask"); }
};

void test() {

	typedef List22<Object*> tObjList;
	List22<Object*> list;
	Object* obj2 = new Object(NULL,"obj2");
	obj2->setURI( URI("wosh123") );
	list.push_back( new Object(NULL,"obj1") );
	list.push_back( obj2 );
	list.push_back( new Object(NULL,"obj3") );
//----------------------------------------------------


	TableSectionWrapper<Object, const std::string&, Variant> tw0(&Object::getName, "Name");
	TableSectionWrapper<Object, const std::string&, Variant> tw1(&Object::getEntityID, "ID");
	TableSectionWrapper<Object, const URI&, URI> tw2(&Object::getURI, "URI");
	Object_TableSectionWrapper tw3;
	TableAdapter<tObjList, Object, 4> trw(list);
	trw.setSection(0, &tw0);
	trw.setSection(1, &tw1);
	trw.setSection(2, &tw2);
	trw.setSection(3, &tw3);

/*
TableRenderer tr(TableAdapter);
tr->selectColumn("Name");
tr->unSelectColumn("URI");
tr->filterBy("Priority", 12, 0);
tr->sortBy("Name", ASC);
Table* oTbl = tr.create();
*/

//----------------------------------------------------
	TableRenderer renderer(&trw);
	renderer.selectSection(1, false);
	Table* oTbl = renderer.create();

//----------------------------------------------------
	for ( unsigned int col=0; col<oTbl->getCols(); ++col ) {
		ISerializable* issss = oTbl->getHeaderHorizontal(col);
		Variant* dsss = dynamic_cast<Variant*>(issss);
		if ( dsss == NULL )
			printf("NULL\t" );
		else
			printf("%s\t", dsss->toString().c_str() );
	}
	printf("\n------------------------------------\n");
	for ( unsigned int row=0; row<oTbl->getRows(); ++row ) {
		for ( unsigned int col=0; col<oTbl->getCols(); ++col ) {
			ISerializable* issss = oTbl->get(row, col);
			if ( issss == NULL )
				printf("NULL\t" );
			else
				printf("%s\t", issss->toString().c_str() );
		 }
		printf("\n");
	 }

int asd = 0;
 }


/*


*/